﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.IO;
using System.Windows.Forms;
using MathNet.Numerics.LinearAlgebra;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml.Serialization;
namespace ImgProcessGui
{  
    //This class is defines all functions that are related 2 dim Matrix
    class MatrixFunctions : System.Object
    {

        //public double[][] mat
        //{
        //    get
        //    {
        //        return my_mat;
        //    }
        //}

        //private double[][] my_mat;
           
        //public int matRows;
        //public int matCols;

        //public Matrix2(int Rows,int Columns)
        //{
        //    matRows = Rows;
        //    matCols = Columns;
        //    my_mat = new double[Rows][];
        //    for (int i = 0; i < Rows; i++)
        //    {
        //        my_mat[i] = new double[Columns];
        //    }
        //}

      /// <summary>
      /// Convert Array2Matrix (Vertical Words - double format)
      /// </summary>
      /// <param name="data">In Bytes</param>
      /// <param name="wordLength"></param>
      /// <returns>Vertical Matrix in double</returns>
      public static Matrix matConvertArr2Mat(byte[] data,int wordLength)
      {
          double[][] matrData = new double[wordLength][];
          for (int words = 0; words < wordLength; words++)
          {
              matrData[words] = new double[data.Length / wordLength];
          }
          for (int words = 0; words < data.Length / wordLength; words++)
          {
              //matrData[words] = new double[wordLength];
              for (int i = 0; i < wordLength; i++)
              {
                  matrData[i][words] = Convert.ToDouble(data[words * wordLength + i]);
              }
          }
          Matrix returned_Mat = new Matrix(matrData);
          return returned_Mat;
      }
        /// <summary>
        /// Join b to matrix a (row dimension determined by matrix a) 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
      public static Matrix GlueMatrixSideBySide(Matrix a, Matrix b)
      {
              Matrix c = new Matrix(a.RowCount, a.ColumnCount + b.ColumnCount);
              c.SetMatrix(0, a.RowCount - 1, 0, a.ColumnCount - 1, a);
              c.SetMatrix(0, a.RowCount - 1, a.ColumnCount, c.ColumnCount - 1, b);
              return c;
         
      }
      /// <summary>
      /// Join b to matrix a (column dimension determined by matrix a) 
      /// </summary>
      /// <param name="a"></param>
      /// <param name="b"></param>
      /// <returns></returns>
      public static Matrix GlueMatrixUpToDown(Matrix a, Matrix b)
      {
          Matrix c = new Matrix(a.RowCount + b.RowCount, a.ColumnCount);
          c.SetMatrix(0, a.RowCount - 1, 0, a.ColumnCount - 1, a);
          c.SetMatrix(a.RowCount,c.RowCount-1, 0, c.ColumnCount - 1, b);
          return c;

      }

        //Filling Matrix With Random Vals
        public static void FillMatrixRandom(int lowerBound, int upperBound,double[][] my_mat)
        {
            CreateRandom randomVec = new CreateRandom(); 
            for (int i = 0; i < my_mat.GetLength(0) ; i++) //running through rows
            {
                my_mat[i] = randomVec.RandomVector_double(my_mat[0].GetLength(0), lowerBound, upperBound);

            }
        
        }

       
        //Filling Blocks of Matrix With Random Arrays - Mat_LUMinMax structure is  [Min Row Mat,Max Row Mat,MaxVal,MinVal,...]
        public static void FillMatrixRandom(int[] Mat_LUMinMax,double[][] my_mat)
        {
            CreateRandom randomVec = new CreateRandom();

            for (int j = 0; j < Mat_LUMinMax.Length;j=j+4)
            {
                for (int i = Mat_LUMinMax[j]; i <= Mat_LUMinMax[j+1]; i++)
                {
                    my_mat[i] = randomVec.RandomVector_double(my_mat[0].GetLength(0), Mat_LUMinMax[j + 2], Mat_LUMinMax[j + 3]);

                }

            
            }
        }

        public static Matrix FillCentersMatrix(int DataLevel,int centersNum,int[] max,int[] min,int centerGroups,bool isFixed)
        {

            Matrix iniCenters = new Matrix(DataLevel, centersNum);
            if (isFixed)
            {
                iniCenters[0, 0] = -255; iniCenters[1, 0] = -255; iniCenters[2, 0] = -255; iniCenters[3, 0] = -255; iniCenters[4, 0] = -255; iniCenters[5, 0] = -255;
                iniCenters[0, 1] = -220; iniCenters[1, 1] = -220; iniCenters[2, 1] = -220; iniCenters[3, 1] = -220; iniCenters[4, 1] = -220; iniCenters[5, 1] = -220;
                iniCenters[0, 2] = -50; iniCenters[1, 2] = -50; iniCenters[2, 2] = -50; iniCenters[3, 2] = -50; iniCenters[4, 2] = -50; iniCenters[5, 2] = -50;
                iniCenters[0, 3] = 50; iniCenters[1, 3] = 50; iniCenters[2, 3] = 50; iniCenters[3, 3] = 50; iniCenters[4, 3] = 50; iniCenters[5, 3] = 50;
                iniCenters[0, 4] = 220; iniCenters[1, 4] = 220; iniCenters[2, 4] = 220; iniCenters[3, 4] = 220; iniCenters[4, 4] = 220; iniCenters[5, 4] = 220;
                iniCenters[0, 5] = 255; iniCenters[1, 5] = 255; iniCenters[2, 5] = 255; iniCenters[3, 5] = 255; iniCenters[4, 5] = 255; iniCenters[5, 5] = 255;
            }
            else
            {
                Random rand = new Random();
                for (int col = 0; col < centersNum; col++)
                {
                    for (int row = 0; row < DataLevel; row++)
                    {
                        int grp = col % centerGroups;
                        iniCenters[row, col] = rand.Next(min[grp], max[grp]);
                    }

                }
            }
            return iniCenters;
        }

        public static void FillMinMax(int[] min,int[] max,int totalMin,int totalMax,int grpVariance,int centerGroups)
        {
            Random rand = new Random();
            int distance = Math.Abs((totalMax-grpVariance) - totalMin)/centerGroups;
            for(int grp = 0;grp < centerGroups;grp++)
            {
                int grpRange = totalMin + grp * distance;
                min[grp] = rand.Next(grpRange, grpRange + distance);
                max[grp] = min[grp] + grpVariance;
            }

        }

        //public void PrintMatToConsole()
        //{
        //    Console.WriteLine("");
        //    for (int i = 0; i < matRows; i++)
        //    {
        //        for (int j = 0; j < matCols; j++)
        //        {

        //            Console.Write("{0,20}", my_mat[i][j]);
        //        }
        //        Console.WriteLine();

        //    }
        //}
        
        /// <summary>
        /// This function saves matrix in debug\csv Dir (As Csv File)
        /// </summary>
        /// <param name="mat">Matrix 2 save</param>
        /// <param name="fileName">File name without extension</param>
        public void PrintMatToFile(double[][] mat, string fileName)
        {
            StreamWriter sw = new StreamWriter(@"C:\Program Files\IdentifierFiles\CSV\" + fileName.ToString() + @".csv");
            for (int i = 0; i < mat.GetLength(0); i++)
            {
                for (int j = 0; j < mat[0].GetLength(0); j++)
                {

                    sw.Write(mat[i][j] + ",");
                }
                sw.WriteLine();

            }
            sw.Close();
        }

        public void SaveMatrix(string Dir,string fileName,Matrix mat2Save)
        {
            BinaryFormatter bf = new BinaryFormatter();
            FileStream writer = new FileStream(@"C:\Program Files\IdentifierFiles\" + Dir + @"\" + fileName + @".dat", FileMode.OpenOrCreate);
            bf.Serialize(writer, mat2Save.GetArray());
            writer.Close();
        }

        public void LoadMatrix(string Dir,string fileName, out Matrix mat2Read)
        {

            BinaryFormatter bf = new BinaryFormatter();
            FileStream reader = new FileStream(@"C:\Program Files\IdentifierFiles\" + Dir + @"\" + fileName + @".dat", FileMode.Open);
            mat2Read = new Matrix((double[][])bf.Deserialize(reader));
            reader.Close();
        }




        //Clone other matrix
        //public void CloneMatrix(int lowerBound, int upperBound, double[][] CloneThis)
        //{
        //    for (int i = 0; i < matRows; i++)
        //    {
        //        for (int j = 0; j < matCols; j++)
        //        {
        //            my_mat[i][j] = CloneThis[i][j];
        //        }

        //    }

        //}

        //public override bool Equals(System.Object obj)
        //{
        //    // If parameter is null return false.
        //    if (obj == null)
        //    {
        //        return false;
        //    }

        //    // If parameter cannot be cast to Point return false.
        //    Matrix2 m = obj as Matrix2;
        //    if ((System.Object)m == null)
        //    {
        //        return false;
        //    }

        //    for (int i = 0; i < matRows; i++)
        //    {
        //        for (int j = 0; j < matCols; j++)
        //        {

        //            if (my_mat[i][j] != m.mat[i][j])
        //            {
        //                return (false);
        //            }
        //        }

        //    }

        //    // Return true if the fields match:
        //    return (true);
        //}

        //public bool Equals(Matrix2 m)
        //{
        //    // If parameter is null return false:
        //    if ((object)m == null)
        //    {
        //        return false;
        //    }

        //    for (int i = 0; i < matRows; i++)
        //    {
        //        for (int j = 0; j < matCols; j++)
        //        {

        //            if (my_mat[i][j] != m.mat[i][j])
        //            {
        //                return (false);
        //            }
        //        }

        //    }
        //    // Return true if the fields match:
        //    return (true);
        //}

        //public override int GetHashCode()
        //{
        //    return ((int)(Algorithems.FindMaxIntArray(my_mat[0]))) * ((int)(Algorithems.FindMinIntArray(my_mat[0]))) * ((int)(Algorithems.FindMaxIntArray(my_mat[1]))) * ((int)(Algorithems.FindMinIntArray(my_mat[1])));
        //}

    }

    class MyVectorFunctions
    {
        public void AddVectors(out double[] VecOut, double[] VecIn1, double[] VecIn2)
        {
            //TODO - Check that vectors are same sized
            VecOut = new double[VecIn1.Length];
            for (int i=0;i < VecIn1.Length;i++)
            {
                VecOut[i] = VecIn1[i]+ VecIn2[i];
            }
        }
        
        public void AvgVector(out double[] VecOut, double[] VecIn, double AvgBy)
        {
            //TODO - Check that vectors are same sized
            VecOut = new double[VecIn.Length];
            for (int i = 0; i < VecIn.Length; i++)
            {
                VecOut[i] = VecIn[i]/AvgBy;
            }
        }
    }
    [Serializable]
    public class progParametes
    {
        
        public void Save()
        {
            XmlSerializer xf = new XmlSerializer(typeof(progParametes));
            FileStream writer = new FileStream(@".\progParametes.xml", FileMode.OpenOrCreate);
            xf.Serialize(writer, instance);
            writer.Close();
        }
        private static progParametes Load()
        {
            progParametes p = null;
            if(File.Exists("progParametes.xml"))
            {
                XmlSerializer xf = new XmlSerializer(typeof(progParametes));
                FileStream reader = new FileStream(@".\progParametes.xml", FileMode.OpenOrCreate);
                p = (progParametes)xf.Deserialize(reader);
                reader.Close();
            }
            else
            {
                p = new progParametes();
            }
            return p;
        }

        private progParametes()
        {
           
        }

        public static progParametes Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = Load();
                }
                return instance;
            }
        }
        private static progParametes instance = null;
        public int FirstwordToIgnore;
        public int SecondwordToIgnore;
    }
}
